게시판용 라이브러리 입니다
소스가 꽤 안정화 됐기 때문에 공개합니다.
역시 LGPL이구요.
LGPL을 꼭 읽어보시고 사용해주시기 바랍니다.
다수의 DB밴더라이브러리를 지원하는 DB클래스와 기타 유틸리티가
들어있습니다.
개선의견 많이 많이 주시면 감사하겠습니다.
<?
/**
* @fileoverview addictlib
* <br>Copyrights ⓒ 2006 GWKPLUS All rights reserved.
* 이 소스는 Addict 프레임워크의 일부분이며 LGPL을 따릅니다.
* @author gwkplus gwkplus@gmail.com
* @version 0.1
*/
require "PreparedStatement.php";
/**
* 데이터소스연결문자열을 해석하여 배열로 반환
* @param string $datasource 데이터소스 문자열
* @return array $ds
* @author gwkplus
*/
function dsparse($datasource)
{
$ds = array();
$datasource = split("://", $datasource);
$ds[dbvender] = $datasource[0];
$datasource = split(":", $datasource[1]);
$ds[hostname] = $datasource[0];
$datasource = split("/", $datasource[1]);
$ds[port] = $datasource[0];
$ds[dbname] = $datasource[1];
return $ds;
}
/**
* 범용 SQL 제한절 만들기
* @return string 쿼리 문자열
* @param string $dbvender 데이터베이스 벤더명
* @param string $sql 쿼리 문자열
* @param number $offset 오프셋 번호
* @param number $count 갯수
* @param string $rownumname 로우번호 필드명
* @author gwkplus
*/
function addLimitStmt($dbvender, $sql, $offset, $count, $rownumname="")
{
$offset_count = $offset + $count;
$rnd = "$offset"."_"."$count";
if($offset < 0)
{
$offset = 0;
}
if($count < 0)
{
$count = 0;
}
switch($dbvender)
{
case "pgsql":
case "mysql":
{
$sql = "$sql limit $offset, $count";
break;
}
case "mssql":
{
$sql =
<<<HEREDOC
select top $count *
from
(
select top $offset_count *
from
(
$sql
) AS subquery1_$rnd
order by $rownumname desc
) AS subquery2_$rnd
order by $rownumname asc
HEREDOC;
break;
}
case "oracle":
{
$count = $offset + $count;
$offset += 1;
$sql =
<<<HEREDOC
select *
from
(
select rownum as numrow_$rnd, subquery1_$rnd.*
from
(
$sql
) AS subquery1_$rnd
)
where
numrow_$rnd between $offset
and $count
HEREDOC;
break;
}
}
return $sql;
}
/**
* @author gwkplus
*/
class AddictDB
{
private $link = null;
private $ds = null;
private $pass = null;
public $lastQuery = null;
/**
* 생성자
* @param string $ds 데이터소스 문자열
* @param string $user 사용자명
* @param string $pass 비밀번호
* @author gwkplus
*/
public function __construct($ds, $user, $pass)
{
$this->ds = dsparse($ds);
$this->ds[user] = $user;
$this->pass = $pass;
$this->connect();
}
/**
* 데이터베이스 연결 함수
* @return object 데이터베이스 연결 객체
* @author gwkplus
*/
public function connect()
{
switch($this->ds[dbvender])
{
case "mysql" :
{
$this->link = mysqli_connect($this->ds[host], $this->ds[user], $this->pass);
break;
}
case "mssql" :
{
$this->link = mssql_connect($this->ds[host], $this->ds[user], $this->pass);
break;
}
case "odbc" :
{
$this->link = odbc_connect($this->ds[host], $this->ds[user], $this->pass);
break;
}
}
$this->select_db($this->ds[dbname]);
return $this->link;
}
/**
* 데이터베이스 선택 함수
* @param string $dbname 데이터베이스명
* @return boolean true = 연결 성공, false = 연결 실패
* @author gwkplus
*/
public function select_db($dbname)
{
switch($this->ds[dbvender])
{
case "mysql" :
{
return mysqli_select_db($this->link, $dbname);
}
case "mssql" :
{
return mssql_select_db($dbname, $this->link);
}
case "odbc" :
{
$this->query("use $dbname");
return true;
}
}
return false;
}
/**
* 데이터베이스용 특수문자 처리
* @param string $escapestr 처리할 문자열
* @return string 처리된 문자열
* @author gwkplus
*/
public function escape_string($escapestr)
{
return mysqli_real_escape_string($this->link,$escapestr);
}
/**
* 트랜잭션을 시작합니다.
* @return boolean true = 성공, false = 실패
* @author gwkplus
*/
function beginTran()
{
switch($this->ds[dbvender])
{
case "mysql":
{
$this->query("BEGIN");
return true;
}
case "mssql":
{
$this->query("BEGIN TRANSACTION");
return true;
}
case "odbc":
{
odbc_autocommit($this->link, false);
return true;
}
}
}
/**
* 트랙잭션을 완료합니다.
* @return boolean true = 성공, false = 실패
* @author gwkplus
*/
function commitTran()
{
switch($this->ds[dbvender])
{
case "mysql":
{
$this->query("COMMIT");
return true;
}
case "mssql":
{
$this->query("COMMIT TRANSACTION");
return true;
}
case "odbc":
{
odbc_commit($this->link);
odbc_autocommit($this->link, true);
return true;
}
}
}
/**
* 트랜잭션을 취소합니다.
* @return boolean true = 성공, false = 실패
* @author gwkplus
*/
function rollbackTran()
{
switch($this->ds[dbvender])
{
case "mysql":
{
$this->query("ROLLBACK");
return true;
}
case "mssql":
{
$this->query("ROLLBACK TRANSACTION");
return true;
}
case "odbc":
{
odbc_rollback($this->link);
return true;
}
}
}
/**
* 쿼리 함수
* @param string $query 쿼리문자열
* @return mixed 각 DB쿼리 함수의 실행결과를 돌려줌
*/
public function query($query)
{
$this->lastQuery = $query;
switch($this->ds[dbvender])
{
case "mysql" :
{
return mysqli_query($this->link, $query);
}
case "mssql" :
{
return mssql_query($query, $this->link);
}
case "odbc" :
{
return odbc_exec($this->link, $query);
}
}
return false;
}
/**
* 쿼리 실행후 결과를 배열에 담아 반환.
* @param string $query 쿼리 문자열
* @return array 결과 배열
* @author gwkplus
*/
public function query_fetch_row($query)
{
$result = $this->query($query);
if($result == null)
{
return null;
}
$row = $this->fetch_row($result);
return $row;
}
/**
* 결과 포인터에서 데이터를 추출해서 배열로 반환.
* @param mixed $result 결과 포인터
* @return array 결과 데이터 배열
* @author gwkplus
*/
public function fetch_row($result)
{
switch($this->ds[dbvender])
{
case "mysql":
{
return mysqli_fetch_row($result);
}
case "mssql":
{
return mssql_fetch_row($result);
}
case "odbc":
{
return odbc_fetch_row($result);
}
}
}
/**
* 결과 포인터로 부터 결과수를 가져온다.
* @param mixed $result 결과 포인터
* @return int 결과행의 수를 가져온다.
*/
public function num_rows($result)
{
switch($this->ds[dbvender])
{
case "mysql":
{
return mysqli_num_rows($result);
}
case "mssql":
{
return mssql_num_rows($result);
}
case "odbc":
{
return odbc_num_rows($result);
}
}
}
/**
* 이전 연산에서 영향받은 로우 갯수 반환
* @param mixed $result 결과 포인터
* @return int 영향받은 행의 수를 반환
*/
public function affected_rows($result)
{
switch($this->ds[dbvender])
{
case "mysql":
{
return mysqli_affected_rows($this->link);
}
case "mssql":
{
return mssql_rows_affected($result);
}
case "odbc":
{
return odbc_num_rows($result);
}
}
}
/**
* 결과 포인터의 메모리를 해제 한다.
* @param mixed $result 결과 포인터
* @return void
*/
public function free_result($result)
{
switch($this->ds[dbvender])
{
case "mysql":
{
mysqli_free_result($result);
}
case "mssql":
{
mssql_free_result($result);
}
case "odbc":
{
odbc_free_result($result);
}
}
}
/**
* 쿼리를 실행하고 결과를 관계배열로 반환한다.
* @param string $query 쿼리문자열
* @return array 관계배열
*/
public function query_fetch_assoc($query)
{
$result = $this->query($query);
if($result==null)
{
return null;
}
$row = $this->fetch_assoc($result);
return $row;
}
public function fetch_assoc($result)
{
switch($this->ds[dbvender])
{
case "mysql" :
{
return mysqli_fetch_assoc($result);
}
case "mssql" :
{
return mssql_fetch_assoc($result);
}
case "odbc" :
{
return odbc_fetch_array($result);
}
}
return null;
}
public function addLimitStmt($sql, $offset, $count, $rownumname = "")
{
return addLimitStmt($this->ds[dbvender], $sql, $offset, $count, $rownumname);
}
}
/**
* 태그 모음
*/
function inputradio($name, $value, $checked, $attributes)
{
if($checked == true) $checked = "checked";
else
{
$checeked = "";
}
return "<input type=radio name='$name' value='$value' $attributes $checked>";
}
function selectoption($value, $text, $selected, $attributes)
{
return "<option value='$value' $attributes $checked>$text</option>";
}
/**
* 공용페이징 계산기
* @param int $resultcount 결과수
* @param int $listlimit 목록제한수
* @param int $pagelimit 페이지제한수
* @param int $pageno 현재 페이지 번호
* @return string 페이징계산에 필요한 변수를 관계배열로 반환
* @author gwkplus
*/
function pagingCalc($resultcount, $listlimit, $pagelimit, $pageno)
{
$p = array();
// 총페이지수
$p['total_page'] = (int)(($resultcount - 1)/$listlimit) + 1;
// 현제 페이지번호
$p['pageno'] = ($pageno < 1) ? 1 : (($pageno > $p['total_page']) ? $p['total_page'] : $pageno);
// 이전 페이지 번호
$p['prev_page'] = $p['pageno'] > 1 ? $p['pageno']-1 : 0;
// 다음 페이지 번호
$p['next_page'] = $p['pageno'] < $p['total_page'] ? $p['pageno'] + 1 : 0;
// 목록 처음 페이지 번호
$p['startpage_list'] = (int)(($p['pageno'] - 1) / $pagelimit) * $pagelimit + 1;
// 목록 마지막 페이지 번호
$p['endpage_list'] = $p['total_page'] > ($p['startpage_list'] + $pagelimit-1) ?
$p['startpage_list'] + $pagelimit - 1 : $p['total_page'];
// 다음 페이지 목록
$p['prev_pagelist'] = $p['startpage_list'] == 1 ? 0 : $p['startpage_list'] - 1;
// 이전 페이지 목록
$p['next_pagelist'] = $p['total_page'] == $p['endpage_list'] ? 0 : $p['endpage_list'] + 1;
$p['resultcount'] = $resultcount;
$p['listlimit'] = $listlimit;
$p['pagelimit'] = $pagelimit;
return $p;
}
/**
* 페이징링크와 관련 정보를 받아서 페이징 링크 문자열로 반환
* @param string $baseUrl 기반 링크 주소
* @param int $resultcount 결과수
* @param int $listlimit 목록제한수
* @param int $pagelimit 페이지제한수
* @param int $pagelistlimit 페이징목록제한수
* @param int $pageno 현재 페이지 번호
* @return string 페이징 링크 문자열
* @author gwkplus
*/
function paging($baseUrl, $resultcount, $listlimit, $pagelimit, $pagelistlimit ,$pageno)
{
$ret_val = "";
$p = pagingCalc($resultcount, $listlimit, $pagelimit ,$pageno);
// 페이징===============================================================================
if($p['prev_page'] > 0)
{
$link = '<a href="?" title="이전 페이지로 이동합니다.">[이전]</a>';
$pstmt = new PreparedStatement($link);
$pstmt->setEval(0, $baseUrl . '&pageno=' . $p['prev_page']);
$ret_val .= $pstmt->toString();
$pstmt = null;
}
else
{
$ret_val .= '<a title="">[이전]</a>';
}
if($p['prev_pagelist'] > 0)
{
$link = ' <a href="?" title="?페이지로 이동합니다.">[이전목록]</a> ';
$pstmt = new PreparedStatement($link);
$pstmt->setEval(0, $baseUrl . '&pageno=' . $p['prev_pagelist']);
$pstmt->setInt(0, $p['prev_pagelist']);
$ret_val .= $pstmt->toString();
$pstmt = null;
}
if($pageno>$pagelimit)
{
$link = '<a href="?" title="첫 페이지로 이동합니다.">[1]</a> ... ';
$pstmt = new PreparedStatement($link);
$pstmt->setEval(0, $baseUrl . '&pageno=1');
$ret_val .= $pstmt->toString();
$pstmt = null;
}
$page_link = "";
for($i = $p['startpage_list']; $i <= $p['endpage_list']; $i++)
{
$page_link = ' <a href=? title="?페이지로 이동합니다.">?</a> ';
$pstmt = new PreparedStatement($page_link);
$pstmt->setString(0, $baseUrl . '&pageno=' . $i);
$pstmt->setInt(0, $i);
if($i == $pageno)
{
$pstmt->setEval(0, "[$i]");
}
else
{
$pstmt->setEval(0, "$i");
}
$ret_val .= $pstmt->toString();
$pstmt = null;
}
if($p['startpage_list'] + $pagelimit <= $p['total_page']
&& ($p['endpage_list'] < $pagelistlimit || $pagelistlimit == 0))
{
if($pagelistlimit != 0)
{
$p['total_page'] = $pagelistlimit;
}
$link = ' ... <a href="?" title="마지막(?) 페이지로 이동합니다.">?</a> ';
$pstmt = new PreparedStatement($link);
$pstmt->setEval(0, $baseUrl . '&pageno=' . $p['total_page']);
$pstmt->setInt(0, $p['total_page']);
$pstmt->setInt(0, $p['total_page']);
$ret_val .= $pstmt->toString();
$pstmt = null;
}
if($p['next_pagelist'] > 0
&& ($p['endpage_list'] < $pagelistlimit || $pagelistlimit == 0))
{
$link = ' <a href="?" title="?페이지로 이동합니다.">[다음목록]</a> ';
$pstmt = new PreparedStatement($link);
$pstmt->setEval(0, $baseUrl . '&pageno=' . $p['next_pagelist']);
$pstmt->setInt(0, $p['next_pagelist']);
$ret_val .= $pstmt->toString();
$pstmt = null;
}
if($p['next_page'] > 0
&& ($pageno < $pagelistlimit || $pagelistlimit == 0))
{
$link = '<a href="?" title="다음 페이지로 이동합니다.">[다음]</a>';
$pstmt = new PreparedStatement($link);
$pstmt->setEval(0, $baseUrl . '&pageno=' . $p['next_page']);
$ret_val .= $pstmt->toString();
$pstmt = null;
}
else
{
$ret_val .= '<a title="">[다음]</a>';
}
// 페이징===============================================================================
$p = null;
return $ret_val;
}
/**
* HTTP 인증 헤더를 해석하는 함수
* @author gwkplus
*/
function http_digest_parse($txt)
{
// protect against missing data
$needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1);
$data = array();
preg_match_all('@(\w+)=(?:([\'"])([^\2]+)\2|([^\s,]+))@', $txt, $matches, PREG_SET_ORDER);
foreach ($matches as $m) {
$data[$m[1]] = $m[3] ? $m[3] : $m[4];
unset($needed_parts[$m[1]]);
}
return $needed_parts ? false : $data;
}
/**
* HTTP 인증 요구 헤더들을 전송합니다.
* @author gwkplus
*/
function sendHttpAuthHeaders($realm)
{
$nonce = "Ny8yLzIwMDIgMzoyNjoyNCBQTQ";
header('HTTP/1.0 401 Unauthorized');
Header("WWW-authenticate: basic realm=\"$realm\"");
//Header("WWW-Authenticate: Digest realm=\"$realm\", nonce=\"$nonce\", algorithm=MD5, qop=\"auth\"");
}
/**
* HTTP 이어받기를 위한 헤더들을 전송합니다.
* @author gwkplus
*/
function sendHttpRangeHeaders($filepath, $filename="", $seek_start=0)
{
$filesize = filesize($filepath);
$filesize_1 = $filesize-1;
$filedate = gmdate('D, d M Y H:i:s \G\M\T', filemtime($filepath));
header("Last-Modified: $filedate");
header("Accept-Ranges: bytes");
if($filename != "")
{
}
else
{
}
header("content-disposition: attachment; filename=\"$filename\"");
header("Content-Length: " . ($filesize-$seek_start));
/**
* TODO LIST
* . unique 하면서도 바뀌지 않는 id를 만들어보자.
* header("ETag: \"6c02b-2cb3f52-68a29e00\"");
*/
if($seek_start > 0
&& $seek_start < $filesize_1)
{
header("Content-Range: bytes $seek_start-$filesize_1/$filesize");
}
header("Content-Type: application/unknown");
return true;
}
/**
* 사이즈를 읽기 형식으로 반환합니다.
* @param int $size 바이트 사이즈
* @author gwkplus
*/
function addict_toHumanSize($size)
{
$G = (1024*1024*1024);
$M = (1024*1024);
$K = (1024);
$type = "";
$size = (float)$size;
if($size >= $G)
{
$size = (float)($size)/$G;
$type = "G";
}
else if($size >= $M)
{
$size = (float)($size)/$M;
$type = "M";
}
else if($size >= $K)
{
$size = (float)($size)/$K;
$type = "K";
}
else
{
$type = "K";
}
$pos = strpos($size, ".");
if($pos > 0)
{
$size = substr($size,0,$pos+3);
}
return $size.$type;
}
/**
* DiskUsage
* @param string $path 경로 문자열
* @param string $option 옵션
* @return 디스크 사용량을 반환합니다.
* @author gwkplus
*/
function addict_du($path, $option = "")
{
$ret_val = exec("du -s$option $path");
$ret_val = split("\t", $ret_val);
$ret_val = $ret_val[0];
if($ret_val == "") return "0K";
return $ret_val;
}
/**
* 지정한 경로의 파일개수를 반환 합니다.
* @param string $path 경로 문자열
* @param string $option 옵션 문자열
* @return int 파일갯수
* @author gwkplus
*/
function addict_filecount($path = ".", $option = "-")
{
if($option != "d")
{
$option = "-";
}
$ret_val = exec("ls -AlR $path | grep \"^$option\" | wc -l");
if($ret_val == "") return 0;
return $ret_val;
}
/**
* 둥근 외곽선
* @author gwkplus
*/
function addict_getRoundBorder($imgUrl, $size, $style = "")
{
if($style!="")
{
return
<<<HEREDOC
<table id="$randomid" border=0 cellpadding=0 cellspacing=0 $event style="$style">
<tr>
<td width=$size height=$size style="background:url($imgUrl/slt.jpg)"></td>
<td height=$size style="background:url($imgUrl/st.jpg)"></td>
<td width=$size height=$size style="background:url($imgUrl/srt.jpg)"></td>
</tr>
<tr>
<td width=$size style="background:url($imgUrl/sl.jpg)"></td>
<td>
HEREDOC;
}// end if
return
<<<HEREDOC
</td>
<td width=$size style="background:url($imgUrl/sr.jpg)"></td>
</tr>
<tr>
<td width=$size height=$size style="background:url($imgUrl/slb.jpg)"></td>
<td height=$size style="background:url($imgUrl/sb.jpg)"></td>
<td width=$size height=$size style="background:url($imgUrl/srb.jpg)"></td>
</tr>
</table>
HEREDOC;
}// end function
/**
* 주민등록 번호로 나이를 계산합니다.
* 주의)만 나이 계산이 아님
*/
function addict_pidAge($pid1, $pid2)
{
if($pid1 == "")
{
return 0;
}
$pid = $pid1.$pid2;
$year = (int)($pid[0].$pid[1]);
$sex = 6;
if($pid[$sex] == 1
|| $pid[$sex] == 2)
{
$year += 1900;
}
else if($pid[$sex] == 3
|| $pid[$sex] == 4)
{
$year += 2000;
}
$age = (int)date("Y")-$year;
return $age;
}
function addict_pidcheck($pid1, $pid2="")
{
$mod = array();
$mod[0] = 31;$mod[1] = 29;$mod[2] = 31;
$mod[3] = 30;$mod[4] = 31;$mod[5] = 30;
$mod[6] = 31;$mod[7] = 31;$mod[8] = 30;
$mod[9] = 31;$mod[10] = 30;$mod[11] = 31;
$sex = 6;
$check = 12;
$pid = $pid1.$pid2;
$checknums = "234567892345";
if(strlen($pid)==13)
{
/**
* 성별체크
*/
if($pid[$sex] > 4
|| $pid[$sex] < 1)
{
return false;
}
/**
* 년월일 체크
*/
$month = (int)($pid[2].$pid[3]);
$day = (int)($pid[4].$pid[5]);
if($month > 12
|| $month < 1
|| $mod[$month] < $day
|| $day < 1)
{
return false;
}
/**
* 주민등록 번호 체크섬 확인
*/
return true; // 체크섬 사용안함
$sum = 0;
for($i = 0; $i<13; $i++)
{
$sum += ($pid[$i]*$checknums[$i]);
}
if(($sum%11) == 0)
{
return 1 == $pid[$check];
}
return (11-($sum%11) == $pid[$check]);
}
return false;
}// end function
function addict_sendmail($to, $from, $subject, $message, $contentType = "text/html")
{
$headers = "From: $from\n";
$headers .= "Content-Type: text/html; charset=ks_c_5601-1987\n";
$headers .= "Content-Transfer-Encoding: base64\n";
$subject = "=?ks_c_5601-1987?B?".base64_encode($subject)."?=";
$message = base64_encode($message);
mail($to, $subject, $message, $headers);
}// end function
/*
class Exception
{
protected $message = 'Unknown exception'; // exception message
protected $code = 0; // user defined exception code
protected $file; // source filename of exception
protected $line; // source line of exception
function __construct($message = null, $code = 0);
final function getMessage(); // message of exception
final function getCode(); // code of exception
final function getFile(); // source filename
final function getLine(); // source line
final function getTrace(); // an array of the backtrace()
final function getTraceAsString(); // formated string of trace
//Overrideable
function __toString(); // formated string for display
}
*/
class MyException extends Exception
{
// 예외를 재정의해, 메세지를 옵션은 아니고 한다
public function __construct($message, $code = 0) {
// 하등의 코드
// 모두를 올바르고 확실히 대입한다
parent::__construct($message, $code);
}
// 오브젝트의 문자열 표현을 독자적으로 정의한다
public function __toString() {
return __CLASS__ . ": [{$this->code}]: {$this->message}n";
}
}
?>
출처 : http://www.phpschool.com/gnuboard4/bbs/board.php?bo_table=tipntech&wr_id=55800&sca=&sfl=wr_subject%7C%7Cwr_content&stx=php5&sop=and |